home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xlock / pyro.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-09  |  10.9 KB  |  415 lines

  1. #ifndef lint
  2. static char sccsid[] = "@(#)pyro.c    1.1 91/05/24 XLOCK";
  3. #endif
  4. /*-
  5.  * pyro.c - Fireworks for xlock, the X Window System lockscreen.
  6.  *
  7.  * Copyright (c) 1991 by Patrick J. Naughton.
  8.  *
  9.  * See xlock.c for copying information.
  10.  *
  11.  * Revision History:
  12.  * 16-Mar-91: Written. (received from David Brooks, brooks@osf.org).
  13.  */
  14.  
  15. /* The physics of the rockets is a little bogus, but it looks OK.  Each is
  16.  * given an initial velocity impetus.  They decelerate slightly (gravity
  17.  * overcomes the rocket's impulse) and explode as the rocket's main fuse
  18.  * gives out (we could add a ballistic stage, maybe).  The individual
  19.  * stars fan out from the rocket, and they decelerate less quickly.
  20.  * That's called bouyancy, but really it's again a visual preference.
  21.  */
  22.  
  23. #include "xlock.h"
  24. #include <math.h>
  25. #define TWOPI 6.2831853
  26.  
  27. /* Define this >1 to get small rectangles instead of points */
  28. #ifndef STARSIZE
  29. #define STARSIZE 1
  30. #endif
  31.  
  32. #define SILENT 0
  33. #define REDGLARE 1
  34. #define BURSTINGINAIR 2
  35.  
  36. #define CLOUD 0
  37. #define DOUBLECLOUD 1
  38. /* Clearly other types and other fascinating visual effects could be added...*/
  39.  
  40. /* P_xxx parameters represent the reciprocal of the probability... */
  41. #define P_IGNITE 2000        /* ...of ignition per cycle */
  42. #define P_DOUBLECLOUD 10    /* ...of an ignition being double */
  43. #define P_MULTI 75        /* ...of an ignition being several @ once */
  44. #define P_FUSILLADE 250        /* ...of an ignition starting a fusillade */
  45.  
  46. #define ROCKETW 2        /* Dimensions of rocket */
  47. #define ROCKETH 4
  48. #define XVELFACTOR 0.0025    /* Max horizontal velocity / screen width */
  49. #define MINYVELFACTOR 0.016    /* Min vertical velocity / screen height */
  50. #define MAXYVELFACTOR 0.018
  51. #define GRAVFACTOR 0.0002    /* delta v / screen height */
  52. #define MINFUSE 50        /* range of fuse lengths for rocket */
  53. #define MAXFUSE 100
  54.  
  55. #define FUSILFACTOR 10        /* Generate fusillade by reducing P_IGNITE */
  56. #define FUSILLEN 100        /* Length of fusillade, in ignitions */
  57.  
  58. #define SVELFACTOR 0.1        /* Max star velocity / yvel */
  59. #define BOUYANCY 0.2        /* Reduction in grav deceleration for stars */
  60. #define MAXSTARS 75        /* Number of stars issued from a shell */
  61. #define MINSTARS 50
  62. #define MINSFUSE 50        /* Range of fuse lengths for stars */
  63. #define MAXSFUSE 100
  64.  
  65. #define INTRAND(min,max) (random()%((max+1)-(min))+(min))
  66. #define FLOATRAND(min,max) ((min)+(random()/MAXRAND)*((max)-(min)))
  67.  
  68. static void ignite();
  69. static void animate();
  70. static void shootup();
  71. static void burst();
  72.  
  73. typedef struct {
  74.     int         state;
  75.     int         shelltype;
  76.     int         color1, color2;
  77.     int         fuse;
  78.     float       xvel, yvel;
  79.     float       x, y;
  80.     int         nstars;
  81. #if STARSIZE > 1
  82.     XRectangle  Xpoints[MAXSTARS];
  83.     XRectangle  Xpoints2[MAXSTARS];
  84. #else
  85.     XPoint      Xpoints[MAXSTARS];
  86.     XPoint      Xpoints2[MAXSTARS];
  87. #endif
  88.     float       sx[MAXSTARS], sy[MAXSTARS];    /* Distance from notional
  89.                          * center  */
  90.     float       sxvel[MAXSTARS], syvel[MAXSTARS];    /* Relative to notional
  91.                              * center */
  92. }           rocket;
  93.  
  94. typedef struct {
  95.     Screen     *scr;
  96.     Colormap    cmap;
  97.     int         p_ignite;
  98.     unsigned long bgpixel;
  99.     unsigned long fgpixel;
  100.     unsigned long rockpixel;
  101.     GC          bgGC;
  102.     int         nflying;
  103.     int         fusilcount;
  104.     int         width, lmargin, rmargin, height;
  105.     float       minvelx, maxvelx;
  106.     float       minvely, maxvely;
  107.     float       maxsvel;
  108.     float       rockdecel, stardecel;
  109.     rocket     *rockq;
  110. }           pyrostruct;
  111.  
  112. static pyrostruct pyros[MAXSCREENS];
  113. static int  orig_p_ignite;
  114. static int  just_started = True;/* Greet the user right away */
  115.  
  116. void
  117. initpyro(win)
  118.     Window      win;
  119. {
  120.     pyrostruct *pp = &pyros[screen];
  121.     rocket     *rp;
  122.     XWindowAttributes xwa;
  123.     XGCValues   xgcv;
  124.     int         rockn, starn, bsize;
  125.  
  126.     XGetWindowAttributes(dsp, win, &xwa);
  127.  
  128.     orig_p_ignite = P_IGNITE / batchcount;
  129.     if (orig_p_ignite <= 0)
  130.     orig_p_ignite = 1;
  131.     pp->p_ignite = orig_p_ignite;
  132.  
  133.     if (!pp->rockq) {
  134.     pp->rockq = (rocket *) malloc(batchcount * sizeof(rocket));
  135.     }
  136.     pp->nflying = pp->fusilcount = 0;
  137.  
  138.     bsize = (xwa.height <= 64) ? 1 : STARSIZE;
  139.     for (rockn = 0, rp = pp->rockq; rockn < batchcount; rockn++, rp++) {
  140.     rp->state = SILENT;
  141. #if STARSIZE > 1
  142.     for (starn = 0; starn < MAXSTARS; starn++) {
  143.         rp->Xpoints[starn].width = rp->Xpoints[starn].height =
  144.         rp->Xpoints2[starn].width = rp->Xpoints2[starn].height = bsize;
  145.     }
  146. #endif
  147.     }
  148.  
  149.     pp->width = xwa.width;
  150.     pp->lmargin = xwa.width / 4;
  151.     pp->rmargin = xwa.width - pp->lmargin;
  152.     pp->height = xwa.height;
  153.     pp->scr = ScreenOfDisplay(dsp, screen);
  154.     pp->cmap = DefaultColormapOfScreen(pp->scr);
  155.  
  156.     pp->fgpixel = WhitePixelOfScreen(pp->scr);
  157.     pp->bgpixel = BlackPixelOfScreen(pp->scr);
  158.     if (!mono && Scr[screen].npixels > 3)
  159.     pp->rockpixel = Scr[screen].pixels[3];    /* Just the right shade of
  160.                          * orange */
  161.     else
  162.     pp->rockpixel = pp->fgpixel;
  163.  
  164.     if (!pp->bgGC) {
  165.     xgcv.foreground = pp->bgpixel;
  166.     pp->bgGC = XCreateGC(dsp, win, GCForeground, &xgcv);
  167.     }
  168. /* Geometry-dependent physical data: */
  169.     pp->maxvelx = (float) (xwa.width) * XVELFACTOR;
  170.     pp->minvelx = -pp->maxvelx;
  171.     pp->minvely = -(float) (xwa.height) * MINYVELFACTOR;
  172.     pp->maxvely = -(float) (xwa.height) * MAXYVELFACTOR;
  173.     pp->maxsvel = pp->minvely * SVELFACTOR;
  174.     pp->rockdecel = (float) (pp->height) * GRAVFACTOR;
  175.     pp->stardecel = pp->rockdecel * BOUYANCY;
  176.  
  177.     XFillRectangle(dsp, win, pp->bgGC, 0, 0, xwa.width, xwa.height);
  178. }
  179.  
  180. /*ARGSUSED*/
  181. void
  182. drawpyro(win)
  183.     Window      win;
  184. {
  185.     pyrostruct *pp = &pyros[screen];
  186.     rocket     *rp;
  187.     int         rockn;
  188.  
  189.     if (just_started || (random() % pp->p_ignite == 0)) {
  190.     just_started = False;
  191.     if (random() % P_FUSILLADE == 0) {
  192.         pp->p_ignite = orig_p_ignite / FUSILFACTOR;
  193.         pp->fusilcount = INTRAND(FUSILLEN * 9 / 10, FUSILLEN * 11 / 10);
  194.     }
  195.     ignite(pp);
  196.     if (pp->fusilcount > 0) {
  197.         if (--pp->fusilcount == 0)
  198.         pp->p_ignite = orig_p_ignite;
  199.     }
  200.     }
  201.     for (rockn = pp->nflying, rp = pp->rockq; rockn > 0; rp++) {
  202.     if (rp->state != SILENT) {
  203.         animate(win, pp, rp);
  204.         rockn--;
  205.     }
  206.     }
  207. }
  208.  
  209. static void
  210. ignite(pp)
  211.     pyrostruct *pp;
  212. {
  213.     rocket     *rp;
  214.     int         multi, fuse, npix, pix;
  215.     float       xvel, yvel, x;
  216.  
  217.     x = random() % pp->width;
  218.     xvel = FLOATRAND(-pp->maxvelx, pp->maxvelx);
  219. /* All this to stop too many rockets going offscreen: */
  220.     if (x < pp->lmargin && xvel < 0.0 || x > pp->rmargin && xvel > 0.0)
  221.     xvel = -xvel;
  222.     yvel = FLOATRAND(pp->minvely, pp->maxvely);
  223.     fuse = INTRAND(MINFUSE, MAXFUSE);
  224.  
  225.     if (random() % P_MULTI == 0)
  226.     {
  227.     multi = INTRAND(5, 15);
  228.     }
  229.     else
  230.     {
  231.     multi = 1;
  232.     }
  233.  
  234.     rp = pp->rockq;
  235.  
  236.     while (multi--)
  237.     {
  238.     if (pp->nflying >= batchcount)
  239.         return;
  240.     while (rp->state != SILENT)
  241.         rp++;
  242.     pp->nflying++;
  243.     rp->state = REDGLARE;
  244.  
  245.     if (random() % P_DOUBLECLOUD == 0)
  246.     {
  247.         rp->shelltype = DOUBLECLOUD;
  248.     }
  249.     else
  250.     {
  251.         rp->shelltype = CLOUD;
  252.     }
  253.  
  254.     if (!mono && (npix = Scr[screen].npixels) > 2)
  255.     {
  256.         /*
  257.          * Some of the rockets should burst white, which
  258.          * won't be in the set of colors generated by
  259.          * hsbramp().
  260.          */
  261.         pix = random() % (npix + 1);
  262.  
  263.         if (pix == npix)
  264.         {
  265.         pix = random() % (npix + 1);
  266.         rp->color1 = WhitePixel (dsp, screen);
  267.         rp->color2 = Scr[screen].pixels[pix];
  268.         }
  269.         else
  270.         {
  271.         rp->color1 = Scr[screen].pixels[pix];
  272.         rp->color2 = Scr[screen].pixels[(pix + (npix / 2)) % npix];
  273.         }
  274.     }
  275.     else
  276.     {
  277.         rp->color1 = rp->color2 = WhitePixel(dsp, screen);
  278.     }
  279.  
  280.     rp->xvel = xvel;
  281.     rp->yvel = FLOATRAND(yvel * 0.97, yvel * 1.03);
  282.     rp->fuse = INTRAND((fuse * 90) / 100, (fuse * 110) / 100);
  283.     rp->x = x + FLOATRAND(multi * 7.6, multi * 8.4);
  284.     rp->y = pp->height - 1;
  285.         rp->nstars = INTRAND(MINSTARS, MAXSTARS);
  286.     }
  287. }
  288.  
  289. static void
  290. animate(win, pp, rp)
  291.     Window      win;
  292.     pyrostruct *pp;
  293.     rocket     *rp;
  294. {
  295.     int         starn;
  296.     float       r, theta;
  297.  
  298.     if (rp->state == REDGLARE) {
  299.     shootup(win, pp, rp);
  300.  
  301. /* Handle setup for explosion */
  302.     if (rp->state == BURSTINGINAIR) {
  303.         for (starn = 0; starn < rp->nstars; starn++) {
  304.         rp->sx[starn] = rp->sy[starn] = 0.0;
  305.         rp->Xpoints[starn].x = (int) rp->x;
  306.         rp->Xpoints[starn].y = (int) rp->y;
  307.         if (rp->shelltype == DOUBLECLOUD) {
  308.             rp->Xpoints2[starn].x = (int) rp->x;
  309.             rp->Xpoints2[starn].y = (int) rp->y;
  310.         }
  311. /* This isn't accurate solid geometry, but it looks OK. */
  312.  
  313.         r = FLOATRAND(0.0, pp->maxsvel);
  314.         theta = FLOATRAND(0.0, TWOPI);
  315.         rp->sxvel[starn] = r * cos(theta);
  316.         rp->syvel[starn] = r * sin(theta);
  317.         }
  318.         rp->fuse = INTRAND(MINSFUSE, MAXSFUSE);
  319.     }
  320.     }
  321.     if (rp->state == BURSTINGINAIR) {
  322.     burst(win, pp, rp);
  323.     }
  324. }
  325.  
  326. static void
  327. shootup(win, pp, rp)
  328.     Window      win;
  329.     pyrostruct *pp;
  330.     rocket     *rp;
  331. {
  332.     XFillRectangle(dsp, win, pp->bgGC, (int) (rp->x), (int) (rp->y),
  333.            ROCKETW, ROCKETH + 3);
  334.  
  335.     if (rp->fuse-- <= 0) {
  336.     rp->state = BURSTINGINAIR;
  337.     return;
  338.     }
  339.     rp->x += rp->xvel;
  340.     rp->y += rp->yvel;
  341.     rp->yvel += pp->rockdecel;
  342.     XSetForeground(dsp, Scr[screen].gc, pp->rockpixel);
  343.     XFillRectangle(dsp, win, Scr[screen].gc, (int) (rp->x), (int) (rp->y),
  344.            ROCKETW, ROCKETH + random() % 4);
  345. }
  346.  
  347. static void
  348. burst(win, pp, rp)
  349.     Window      win;
  350.     pyrostruct *pp;
  351.     rocket     *rp;
  352. {
  353.     register int starn;
  354.     register int nstars, stype;
  355.     register float rx, ry, sd;    /* Help compiler optimize :-) */
  356.     register float sx, sy;
  357.  
  358.     nstars = rp->nstars;
  359.     stype = rp->shelltype;
  360.  
  361. #if STARSIZE > 1
  362.     XFillRectangles(dsp, win, pp->bgGC, rp->Xpoints, nstars);
  363.     if (stype == DOUBLECLOUD)
  364.     XFillRectangles(dsp, win, pp->bgGC, rp->Xpoints2, nstars);
  365. #else
  366.     XDrawPoints(dsp, win, pp->bgGC, rp->Xpoints, nstars, CoordModeOrigin);
  367.     if (stype == DOUBLECLOUD)
  368.     XDrawPoints(dsp, win, pp->bgGC, rp->Xpoints2, nstars, CoordModeOrigin);
  369. #endif
  370.  
  371.     if (rp->fuse-- <= 0) {
  372.     rp->state = SILENT;
  373.     pp->nflying--;
  374.     return;
  375.     }
  376. /* Stagger the stars' decay */
  377.     if (rp->fuse <= 7) {
  378.     if ((rp->nstars = nstars = nstars * 90 / 100) == 0)
  379.         return;
  380.     }
  381.     rx = rp->x;
  382.     ry = rp->y;
  383.     sd = pp->stardecel;
  384.     for (starn = 0; starn < nstars; starn++) {
  385.     sx = rp->sx[starn] += rp->sxvel[starn];
  386.     sy = rp->sy[starn] += rp->syvel[starn];
  387.     rp->syvel[starn] += sd;
  388.     rp->Xpoints[starn].x = (int) (rx + sx);
  389.     rp->Xpoints[starn].y = (int) (ry + sy);
  390.     if (stype == DOUBLECLOUD) {
  391.         rp->Xpoints2[starn].x = (int) (rx + 1.7 * sx);
  392.         rp->Xpoints2[starn].y = (int) (ry + 1.7 * sy);
  393.     }
  394.     }
  395.     rp->x = rx + rp->xvel;
  396.     rp->y = ry + rp->yvel;
  397.     rp->yvel += sd;
  398.  
  399.     XSetForeground(dsp, Scr[screen].gc, rp->color1);
  400. #if STARSIZE > 1
  401.     XFillRectangles(dsp, win, Scr[screen].gc, rp->Xpoints, nstars);
  402.     if (stype == DOUBLECLOUD) {
  403.     XSetForeground(dsp, Scr[screen].gc, rp->color2);
  404.     XFillRectangles(dsp, win, Scr[screen].gc, rp->Xpoints2, nstars);
  405.     }
  406. #else
  407.     XDrawPoints(dsp, win, Scr[screen].gc, rp->Xpoints, nstars, CoordModeOrigin);
  408.     if (stype == DOUBLECLOUD) {
  409.     XSetForeground(dsp, Scr[screen].gc, rp->color2);
  410.     XDrawPoints(dsp, win, Scr[screen].gc, rp->Xpoints2, nstars,
  411.             CoordModeOrigin);
  412.     }
  413. #endif
  414. }
  415.